package com.itcast.controller;



import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.itcast.health.pojo.Result;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Enumeration;

/**
 * @author: lei
 * @version: V1.0
 * @date: 2019/12/3 11:07
 * @description: com.itheima.controller
 * 日志拦截器
 */
@Component
@Aspect
public class CustomInterceptor {
    //使用指定类初始化日志对象
    private Logger logger = LoggerFactory.getLogger(this.getClass());
    //ThreadLocal中存的是HttpServletRequest,也就是请求中的数据
    ThreadLocal<HttpServletRequest> requestThreadLocal = new ThreadLocal();
    //ThreadLocal中存的是long类型的数字
    ThreadLocal<Long> startTime = new ThreadLocal();



    //使用@Pointcut注解声明切入点表达式
    @Pointcut("execution(public * com.itcast.controller.*.*(..))"+
            "&& !execution(public * com.itcast.controller.SpringSecurityUserService.*(..))")

    public void picaLog() {
    }

    //环绕通知
    @Around("picaLog()")
    public Object doAround(ProceedingJoinPoint point) throws Throwable {
        //从spring  上下文中获取
        User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        if (user==null || user.getUsername().equals("")){
            logger.info("用户名未登录");
        }
        logger.info("用户名为:"+user.getUsername());

        //从持有上下文的Request容器中获取requestAttributes
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        //从requestAttributes中获取请求
        HttpServletRequest request = requestAttributes.getRequest();
        //将request中的信息放置在requestThreadLocal
        requestThreadLocal.set(request);
        //将当前的时间以
        startTime.set(System.currentTimeMillis());
        logger.info("---------------------------->");
        //打印日志
        logger.info("request start: " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
        //输出请求头信息
        processRequestHeader();
        //处理请求参数并执行
        processRequestParams(point);
        //执行该方法的结果
        Object result = point.proceed();
        if (result != null) {
            //响应结果
            logger.info("request result: " + JSONObject.toJSONString(result));
        }
        logger.info("request spent time: " + (System.currentTimeMillis() - startTime.get()));
        return result;
    }

    /**
     * 处理请求参数
     * @param point
     */
    private void processRequestParams(ProceedingJoinPoint point) {
        String params = null;
        HttpServletRequest request = requestThreadLocal.get();
        String url = request.getRequestURI();
        String method = request.getMethod();
        //如果是get请求
        if ("GET".equalsIgnoreCase(method)) {
            params = request.getQueryString();
        } else if (!checkFileUpload()) {
            Object[] args = point.getArgs();
            params = JSONArray.toJSONString(args);
        } else {
            params = "";
        }
        logger.info("request params: url:{},method:{},params:{}",new Object[]{url, method, params});
    }

    /**
     * 判断是否是文件上传
     * @return
     */
    private boolean checkFileUpload() {
        return ServletFileUpload.isMultipartContent(requestThreadLocal.get());
    }

    /**
     * 处理请求头信息
     */
    private void processRequestHeader() {
        JSONObject jsonObject = new JSONObject();
        HttpServletRequest request = requestThreadLocal.get();
        Enumeration<String> headerNames = request.getHeaderNames();
        while (headerNames.hasMoreElements()) {
            String key = headerNames.nextElement();
            String value = request.getHeader(key);
            jsonObject.put(key, value);
        }
        logger.info("request header: " + jsonObject.toString());
    }

}
